﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Command;
using XamlingCore.Infrastructure.Navigation;
using XamlingCore.Infrastructure.View.Implementation;
using XamlingCore.Infrastructure.View.Interface;

namespace XamlingCore.Infrastructure.View
{
    [DataContract]
    public class XFrameViewModelBase : ViewModelBase, IActiveAware
    {
        private XNavigationService navigationService;

        public RelayCommand NavigateBackCommand { get; set; }

        private bool isLoading;

        public string Title { get; set; }
        public string Description { get; set; }

        private bool transitionsEnabled = true;

        protected internal bool IsReactivated;

        public XFrameViewModelBase SuperParentModel { get; set; }

        public static XFrameViewModelBase RootFrame { get; protected internal set; }

        public event EventHandler Navigated;

        [DataMember]
        public ObservableCollection<XFrameViewModelBase> ChildFrames { get; set; }

        protected internal List<Type> KnownTypes = new List<Type>();

        public XFrameViewModelBase()
        {
            Guid = System.Guid.NewGuid();
            NavigateBackCommand = new RelayCommand(NavigateBack);

            ChildFrames = new ObservableCollection<XFrameViewModelBase>();
            NavigationService = new XNavigationService();
        }

        internal XFrameViewModelBase FindModel(Guid guid)
        {
            if (Guid == guid)
            {
                return this;
            }

            if (SuperParentModel != null && SuperParentModel.Guid == guid)
            {
                return SuperParentModel;
            }

            if (RootFrame.Guid == guid)
            {
                return RootFrame;
            }

            foreach (var childFrame in ChildFrames)
            {
                var frame = childFrame.FindModel(guid);
                
                if (frame != null)
                {
                    return frame;
                }
            }

            return null;
        }

        public static T CreateRootFrame<T>()
            where T : XFrameViewModelBase, new()
        {
            var obj = new T();
            obj.KnownTypes.Add(typeof(T));
            obj.OnInitialise();
            RootFrame = obj;
            return obj;
        }

        public T CreateChildFrame<T>(Action<T> initialisedCallback)
            where T : XFrameViewModelBase, new()
        {
            var obj = new T();

            obj.SuperParentModel = this;

            ChildFrames.Add(obj);

            if (initialisedCallback != null) initialisedCallback(obj);

            //find the root parent model
            var rootModel = this;

            while (rootModel.ParentModel != null && rootModel.ParentModel != rootModel)
            {
                rootModel = rootModel.ParentModel;
            }

            rootModel.KnownTypes.Add(typeof(T));

            obj.SuperParentModel = this;

            Application.Current.RootVisual.Dispatcher.BeginInvoke(() =>
            {
                obj.OnInitialise();
            });
            return obj;
        }

        public T CreateContentModel<T>()
             where T : XContentViewModelBase, new()
        {
            return CreateContentModel<T>(null);
        }

        public T CreateContentModel<T>(Action<T> initialisedCallback)
             where T : XContentViewModelBase, new()
        {
            var rootModel = this.ParentModel;

            while (rootModel.ParentModel != null && rootModel.ParentModel != rootModel)
            {
                rootModel = rootModel.ParentModel;
            }

            rootModel.KnownTypes.Add(typeof(T));

            var obj = new T { ParentModel = this };

            if (initialisedCallback != null) initialisedCallback(obj);

            obj.IsReady = true;

            obj.OnInitialise();


            return obj;
        }

        public XContentViewModelBase CreateContentModel(string typeName, Action<XContentViewModelBase> initialisedCallback)
        {
            var rootModel = this.ParentModel;

            while (rootModel.ParentModel != null && rootModel.ParentModel != rootModel)
            {
                rootModel = rootModel.ParentModel;
            }

            Type type = Type.GetType(typeName);

            rootModel.KnownTypes.Add(type);

            var obj = Activator.CreateInstance(type) as XContentViewModelBase;


            obj.ParentModel = this;

            if (initialisedCallback != null) initialisedCallback(obj);

            obj.IsReady = true;

            obj.OnInitialise();


            return obj;
        }

        public string Serialise()
        {
            var result = Serialisation.Serialise.SerialiseEntity(this, KnownTypes);

            return result;
        }

        public virtual void OnInitialise() { }
        public virtual void OnReactivate(Action ready) { }
        //internal protected virtual void OnReactivate() { }
        //internal protected virtual void OnDeactivate() { }
        //internal protected virtual void OnBeforeActivate() { }

        void navigationService_Navigated(object sender, System.EventArgs e)
        {
            OnPropertyChanged("BackEnabled");
            OnPropertyChanged("BackVisible");
            
            if (Navigated != null)
            {
                Navigated(this, EventArgs.Empty);
            }
        }

        public XFrameViewModelBase ParentModel
        {
            get
            {
                if (SuperParentModel != null)
                {
                    return SuperParentModel;
                }

                return this;
            }
        }

        public bool BackEnabled
        {
            get { return NavigationService.CanGoBack; }
        }

        public Visibility BackVisible
        {
            get
            {
                return BackEnabled ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        public bool IsLoading
        {
            get
            {
                if (SuperParentModel != null)
                {
                    return SuperParentModel.IsLoading;
                }
                return isLoading;
            }
            set
            {
                if (SuperParentModel != null)
                {
                    SuperParentModel.IsLoading = value;
                }
                isLoading = value;
                OnPropertyChanged("IsLoading");
            }
        }

        [DataMember]
        public bool TransitionsEnabled
        {
            get { return transitionsEnabled; }
            set
            {
                transitionsEnabled = value;
                OnPropertyChanged("TransitionsEnabled");
            }
        }

        [DataMember]
        public Guid Guid { get; set; }

        [DataMember]
        public XNavigationService NavigationService
        {
            get { return navigationService; }
            set
            {
                if (navigationService != null)
                {
                    navigationService.Navigated -= new System.EventHandler(navigationService_Navigated);
                }

                navigationService = value;
                OnPropertyChanged("NavigationService");
                navigationService.Navigated += new System.EventHandler(navigationService_Navigated);
            }
        }

        #region NavigationShortcuts

        public void NavigateTo(object content)
        {
            NavigationService.NavigateTo(content, false);
        }


        public void NavigateTo(object content, bool noHistory)
        {
            NavigationService.NavigateTo(content, noHistory, false);
        }

        public void NavigateTo(object content, bool noHistory, bool forceBack)
        {
            NavigationService.NavigateTo(content, noHistory, forceBack);
        }

        public void NavigateBack()
        {
            NavigationService.NavigateBack(false);
        }

        public void NavigateBack(bool allowNullNavigation)
        {
            NavigationService.NavigateBack(allowNullNavigation);
        }

        #endregion

        #region ShowDialogShortcuts

        public override void ShowDialog(ShowDialogViewModelBase dialogViewModel, System.TimeSpan timeOut, System.Action<Dialog.DialogResult> dialogResult)
        {
            if (SuperParentModel != null)
            {
                SuperParentModel.ShowDialog(dialogViewModel, timeOut, dialogResult);
            }
            else
            {
                base.ShowDialog(dialogViewModel, timeOut, dialogResult);
            }
        }

        public override void HideDialog()
        {
            if (SuperParentModel != null)
            {
                SuperParentModel.HideDialog();
            }
            else
            {
                base.HideDialog();
            }
        }

        #endregion

        public virtual void IsActive(bool activated)
        {
        }
    }


}
